#include "ProjectConfig.hpp"
#include <fmt/format.h>
#include <iostream>
#include <algorithm>

ProjectConfig::ProjectConfig(const std::string & workspace_path)
//从文件将数据导入到数据结构中
  : WorkspacePath(workspace_path)
{
  pugi::xml_document xmldoc;
  std::filesystem::path root_path(workspace_path);
  if(std::filesystem::exists(root_path/"project.xml"))
  //如果文件存在就读取里面的数据
  {
    xmldoc.load_file((root_path/"project.xml").c_str());
    //搜索Project
    pugi::xpath_node_set projectsearch=xmldoc.select_nodes("/Project");
    //预分配大小
    ProjectList.resize(projectsearch.size());
    //遍历元素到列表中
    int count_pos=0;
    for(pugi::xpath_node_set::const_iterator it=projectsearch.begin()
       ;it!=projectsearch.end()
       ;++it,++count_pos)
    //Project层级
    {
      ProjectList[count_pos].name=it->node().attribute("name").value();
      ProjectList[count_pos].describe=it->node().child("Describe").child_value();
      ProjectList[count_pos].path=root_path/(it->node().child("Path").child_value());
      for(pugi::xml_node task=it->node().child("Task");task;task=task.next_sibling("Task"))
      //Task层级
      {
        //读取基础数据
        TaskAttrTable newTableAttr;
        newTableAttr.name=task.attribute("name").value();
        newTableAttr.path=ProjectList[count_pos].path/task.child("Path").child_value();
        //准备原始视频数据
        pugi::xml_node orivideo=task.child("OriVideo");
        for(pugi::xml_node videoItem=orivideo.child("Path");videoItem;videoItem.next_sibling("Path"))
        //OriVideo层级
        {
          TaskElementAttrTable elementTable;
          elementTable.CameraID=videoItem.attribute("ID").value();
          elementTable.path=newTableAttr.path/videoItem.child_value();
          newTableAttr.originVideoList.push_back(std::move(elementTable));
        }
        //添加到列表
        ProjectList[count_pos].taskAttrList.push_back(std::move(newTableAttr));
      }
    }
  }
}

ProjectConfig::~ProjectConfig()
{
  SaveData();
}

void ProjectConfig::CreateProject(const std::string & name,const std::string & dirName,const std::string & describe)
{
  ProjectList.push_back({
      .name=name,
      .path=WorkspacePath/dirName,
      .describe=describe
    });
}

std::vector<std::string> ProjectConfig::GetProjectList()
{
  std::vector<std::string> list(ProjectList.size());
  for(int i=0;i<ProjectList.size();i++)
    list[i]=ProjectList[i].name;
  return std::move(list);
}

bool ProjectConfig::CreateTask(const std::string & project_name,const std::string & name,const std::string & dirName)
{
  auto ptr=std::find_if(ProjectList.begin(),ProjectList.end(),[&project_name](const ProjectAttrTable& prj)->bool{return !strcmp(prj.name.c_str(),project_name.c_str());});
  if(ptr==ProjectList.end())
    return false;
  ptr->taskAttrList.push_back({
    .name=name,
    .path=ptr->path/dirName,
    .originVideoList=std::vector<TaskElementAttrTable>()});
  return true;
}


std::filesystem::path ProjectConfig::GetTaskPath(const std::string & project_name,const std::string & task_name)
{
  auto ptr=std::find_if(ProjectList.begin(),ProjectList.end(),[&project_name](const ProjectAttrTable& prj)->bool{return !strcmp(prj.name.c_str(),project_name.c_str());});
  if(ptr==ProjectList.end())
    return {};
  auto task_ptr=std::find_if(ptr->taskAttrList.begin(),ptr->taskAttrList.end(),[&task_name](const TaskAttrTable& prj)->bool{return !strcmp(prj.name.c_str(),task_name.c_str());});
  if(task_ptr==ptr->taskAttrList.end())
    return {};
  else
    return task_ptr->path;
}

std::vector<std::string> ProjectConfig::GetTaskList(const std::string & project_name)
{
  auto ptr=std::find_if(ProjectList.begin(),ProjectList.end(),[&project_name](const ProjectAttrTable& prj)->bool{return !strcmp(prj.name.c_str(),project_name.c_str());});
  if(ptr==ProjectList.end())
    return {};
  else
  {
    std::vector<std::string> taskList(ptr->taskAttrList.size());
    int newPtr=0;
    for(const auto & i : ptr->taskAttrList)
    {
      taskList.at(newPtr)=i.name;
      newPtr++;
    }
    return std::move(taskList);
  }
}

std::vector<std::string> ProjectConfig::GetTaskOriginVideoList(const std::string & project_name,const std::string & task_name)
{
  auto ptr=std::find_if(ProjectList.begin(),ProjectList.end(),[&project_name](const ProjectAttrTable& prj)->bool{return !strcmp(prj.name.c_str(),project_name.c_str());});
  if(ptr==ProjectList.end())
    return {};
  auto task_ptr=std::find_if(ptr->taskAttrList.begin(),ptr->taskAttrList.end(),[&task_name](const TaskAttrTable& prj)->bool{return !strcmp(prj.name.c_str(),task_name.c_str());});
  if(task_ptr==ptr->taskAttrList.end())
    return {};

  std::vector<std::string> list(task_ptr->originVideoList.size());
  for(int i=0;i<task_ptr->originVideoList.size();i++)
    list[i]=task_ptr->originVideoList[i].CameraID;
  return std::move(list);
}

std::filesystem::path ProjectConfig::GetTaskOriginVideoPath(const std::string & project_name,const std::string & task_name,const std::string & video_name)
{
  auto ptr=std::find_if(ProjectList.begin(),ProjectList.end(),[&project_name](const ProjectAttrTable& prj)->bool{return !strcmp(prj.name.c_str(),project_name.c_str());});
  if(ptr==ProjectList.end())
    return {};
  auto task_ptr=std::find_if(ptr->taskAttrList.begin(),ptr->taskAttrList.end(),[&task_name](const TaskAttrTable& prj)->bool{return !strcmp(prj.name.c_str(),task_name.c_str());});
  if(task_ptr==ptr->taskAttrList.end())
    return {};
  auto video_ptr=std::find_if(task_ptr->originVideoList.begin(),task_ptr->originVideoList.end(),[&video_name](const TaskElementAttrTable& prj)->bool{return !strcmp(prj.CameraID.c_str(),video_name.c_str());});
  if(task_ptr==ptr->taskAttrList.end())
    return {};

  return video_ptr->path;
}

void ProjectConfig::SaveData()
{
  pugi::xml_document xmldoc;
  for(const auto & project_element : ProjectList)
  {
    //添加Project元素
    pugi::xml_node project_node=xmldoc.append_child("Project");
    //添加name属性
    project_node.append_attribute("name")=project_element.name.c_str();
    //添加路径元素
    pugi::xml_node ProjectPath_node=project_node.append_child("Path");
    //设置路径值
    ProjectPath_node.append_child(pugi::node_pcdata).set_value(std::string(project_element.path.filename()).c_str());
    //添加描述
    pugi::xml_node ProjectDescribe_node=project_node.append_child("Describe");
    //设置描述
    ProjectDescribe_node.append_child(pugi::node_pcdata).set_value(project_element.describe.c_str());
    //添加任务列表
    for(const auto & task_element : project_element.taskAttrList)
    {
      pugi::xml_node task_node=project_node.append_child("Task");
      task_node.append_attribute("name")=task_element.name.c_str();
      pugi::xml_node taskChild_node=task_node.append_child("Path");
      taskChild_node.append_child(pugi::node_pcdata).set_value(task_element.path.filename().c_str());
      //设置原始视频
      pugi::xml_node orivideo_node=task_node.append_child("OriVideo");
      for(const auto & orivideo_element : task_element.originVideoList)
      {
        pugi::xml_node orivideoPath_node=orivideo_node.append_child("Path");
        orivideoPath_node.append_attribute("ID")=orivideo_element.CameraID.c_str();
        orivideoPath_node.append_child(pugi::node_pcdata).set_value(orivideo_element.path.filename().c_str());
      }
    }
  }
  xmldoc.save_file((WorkspacePath/"project.xml").c_str());
}

bool ProjectConfig::CreateOriginVideo(const std::string & project_name,const std::string & task_name,const std::string & CameraID,const std::string & fileName)
{
  auto ptr=std::find_if(ProjectList.begin(),ProjectList.end(),[&project_name](const ProjectAttrTable& prj)->bool{return !strcmp(prj.name.c_str(),project_name.c_str());});
  if(ptr==ProjectList.end())
    return false;
  auto task_ptr=std::find_if(ptr->taskAttrList.begin(),ptr->taskAttrList.end(),[&task_name](const TaskAttrTable& prj)->bool{return !strcmp(prj.name.c_str(),task_name.c_str());});
  if(task_ptr==ptr->taskAttrList.end())
    return false;

  task_ptr->originVideoList.push_back({
    CameraID,
    task_ptr->path/fileName
  });
  return true;
}

std::string ProjectConfig::GetProjectPath(const std::string & name)
{
  auto ptr=std::find_if(ProjectList.begin(),ProjectList.end(),[&name](const ProjectAttrTable& prj)->bool{
    return strcmp(prj.name.c_str(),name.c_str())==0;
  });
  if(ptr==ProjectList.end())
    return "";
  else return ptr->path;
}
